package com.xishu.controller;

import com.xishu.annotation.valid.MethodValidator;
import com.xishu.bo.LineUpCodeResponse;
import com.xishu.entity.shop.LineUp;
import com.xishu.entity.shop.LineUpConfig;
import com.xishu.entity.shop.Shop;
import com.xishu.response.ResponseData;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.*;
import com.xishu.socket.WebSocketService;
import com.xishu.util.Tools;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Api(description = "C端或者B端前台排队取号")
@RestController
public class LineUpController implements Tools {
    private static Logger logger = LoggerFactory.getLogger(LineUpController.class);
    private CommonService commonService = CommonService.getInstance();
    private LineUpService lineUpService = LineUpService.getInstance();
    private LockService localLockService = LockService.getInstance();

    @ApiOperation(value = "查询排队情况")
    @PutMapping(value = ("/lineUp"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(mustLogin = false)
    public ResponseData search(@RequestBody LineUp lineUp) throws Exception {
        return CommonService.getInstance().searchResponse(lineUp);
    }

    @ApiOperation(value = "查询某一个排队的排队情况")
    @PutMapping(value = ("/lineUp/code"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(mustLogin = false)
    public ResponseData lineStatus(@RequestBody LineUp lineUp) throws Exception {
        VerifyUtil.verify(() -> lineUp.getShopId() != null);

        if (isNotEmpty(lineUp.getCodeList())) {
            logger.info("find the code list is {}", StringUtils.join(lineUp.getCodeList(), ","));

            List<LineUpCodeResponse> lineUpCodeResponseList = lineUp.getCodeList().stream().map(code -> {
                lineUp.setCode(code);
                return lineUpService.generateLineupCodeResponse(lineUp);
            }).filter(p -> p != null).collect(Collectors.toList());

            return commonService.createResponse(lineUpCodeResponseList);
        } else {
            if (isNotEmpty(lineUp.getCode())) {
                logger.info("only find the code {}", lineUp.getCode());

                LineUpCodeResponse lineUpCodeResponse = lineUpService.generateLineupCodeResponse(lineUp);
                if (lineUpCodeResponse != null) {
                    return commonService.createResponse(lineUpCodeResponse);
                } else {
                    logger.info("empty code result");
                    return ResponseData.emptyResponse();
                }
            }
        }

        logger.info("do not pass the code parameter");
        return ResponseData.emptyResponse();
    }



    @ApiOperation(value = "客人查询自己的排队情况")
    @PutMapping(value = ("/lineUp/status"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(mustLogin = false)
    public ResponseData lining(@RequestBody LineUp reqLineUp) throws Exception {
        VerifyUtil.verify(() -> reqLineUp.getId() != null);
        LineUp lineUp = commonService.searchOne(reqLineUp);

        if (lineUp == null) {
            logger.info("can not find the line up config");
            return ResponseData.emptyResponse();
        }

        if (!getBoolean(lineUp.getLining())) {
            logger.info("line end");
            return commonService.createResponse(lineUp);
        }

        List<LineUp> lineUpList = lineUpService.getLineUpList(lineUp.getShopId(), lineUp.getCode());

        if (isEmpty(lineUpList)) {
            return ResponseData.emptyResponse();
        }

        long frontLineList = lineUpList.stream().filter(p -> p.getSerial() < lineUp.getSerial()).count();
        HashMap<String, Object> map = new HashMap<>();
        map.put("waitingSize", frontLineList);
        map.put("lineNo", lineUp.getCode() + lineUp.getSerial());
        //获取排队配置
        LineUpConfig lineUpConfig = lineUpService.queryLineUpConfig(lineUp.getShopId(), lineUp.getCode());
        VerifyUtil.verify(() -> lineUpConfig != null, ResponseStatus.FOOD_TABLE_CONFIG_NOT_EXIST);
        map.put("waitingTime", frontLineList * getInt(lineUpConfig.getWaitAvgTime()));

        return commonService.createResponse(map);
    }

    @ApiOperation(value = "删除排队情况")
    @DeleteMapping(value = ("/lineUp"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(checkShop = true)
    public ResponseData delete(@RequestBody LineUp lineUp) throws Exception {
        return CommonService.getInstance().delete(lineUp);
    }

    @ApiOperation(value = "创建排队情况，可以是C端，也可以B端前台")
    @PostMapping(value = ("/lineUp"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(mustLogin = false)
    public ResponseData create(@RequestBody LineUp lineUp) throws Exception {
        Long shopId = lineUp.getShopId();
        VerifyUtil.verify(() -> shopId != null);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        VerifyUtil.verify(() -> getBoolean(shop.getBusinessStatus()), ResponseStatus.SHOP_CLOSED);

        Object lock = localLockService.getLock(addTwoKey("lineup", lineUp.getShopId()));

        synchronized (lock) {
            String code = LineUpService.getInstance().getCode(lineUp.getPersons(), lineUp.getShopId());
            lineUp.setCode(code);
            //找出最大的值，然后加1
            int maxSerial = LineUpService.getInstance().getMaxSerial(lineUp.getShopId(), code);
            lineUp.setSerial(maxSerial + 1);
            lineUp.setLining(true);
            ResponseData responseData = CommonService.getInstance().createObject(lineUp);
            WebSocketService.getInstance().sendLineUp(shopId);
            return responseData;
        }
    }

    /**
     * 修改排队信息
     *
     * @param lineUp
     * @return
     */
    @ApiOperation(value = "修改排队信息")
    @PutMapping(value = ("/lineUp/modify"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(checkShop = true)
    public ResponseData modify(@RequestBody LineUp lineUp) throws Exception {
        ResponseData responseData = commonService.modifyObject(lineUp);
        LineUp lineUpInDb = CommonService.getInstance().findEntity(lineUp.getId(), LineUp.class);
        WebSocketService.getInstance().sendLineUp(lineUpInDb.getShopId());
        return responseData;
    }

    @ApiOperation(value = "所有排队里面的当前叫号")
    @PutMapping(value = ("/all/first/lineUp"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(checkShop = true)
    public ResponseData findAllLineUpFirst(@RequestBody LineUp lineUp) throws Exception {
        return commonService.createResponse(lineUpService.getAllCurrentLine(lineUp.getShopId()));
    }
}
